07. Mockito

Mockito

ND079 JPND C3 L5 A05a Introduction To Mockito V3

Why Write our Own Mocks?

Mockito is a framework that can automatically generate mock objects. Mockito uses slightly different definitions for Mock and Spy than we saw earlier:

A Mockito Mock is an object that can programmatically implement any behavior from any of the test doubles we learned earlier. Mockito Mocks can be spies, dummies, stubs, or mocks.

A Mockito Spy can do everything a Mock can do, but it also inherits the behavior of the class it extends. Sometimes this construct is referred to as a partial mock, because it's part mock, part original class.

Mock vs. Spy

Generally, you should only use Mockito Mock. Creating partial mocks is dangerous, because they allow you to override the behavior of the same class you're testing. At best, that means your class is poorly designed, and at worst, it means you've created a unit test that always passes because it defines the very behavior it is testing.

The only reason I've encountered to use Spies is if you need to verify that internal methods are called on your tested class. This usually is evidence of some design problems, but can be unavoidable on some legacy code.

ND079 JPND C3 L5 A05b Demo Mockito

Adding Mockito

First, add the dependency to Maven. Updated dependency information available at https://site.mockito.org

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>3.6.0</version>
    <scope>test</scope>
</dependency>

Next, attach the Mockito test runner to your unit test by using the @ExtendsWith annotation from JUnit 5.

@ExtendWith(MockitoExtension.class)
public class UserServiceMockitoTest {

}

Creating a Mock

Creating a mock in Mockito is as simple as annotating a class attribute with the @Mock annotation. For example, I could create a Mock SalesService using this approach. The code below automatically creates a @Mock SalesService for every unit test and injects it into a new UserService in the init method.

@ExtendWith(MockitoExtension.class)
public class UserServiceMockitoTest {

    private UserService userService;

    @Mock
    private SalesService salesService;

    @BeforeEach
    void init() {
        userService = new UserServiceImpl(salesService);
    }
}

You can also inject the Mock into UserService automatically using the @InjectMocks annotation instead of using a @BeforeEach method.

Writing a Unit Test with Mockito

Our previous test with the FakeSalesService created a fake using the desired value it should return.

   @ParameterizedTest
    @ValueSource(strings={"Fizz", "Buzz", "FizzBuzz"})
    public void fancyBusiness_getsFizzBuzzString_returnsSameString(String returnString) {
        SalesService salesService = new FakeSalesService(returnString);
        UserService userService = new UserServiceImpl(salesService);

        //which number we pass doesn't matter, because we're controlling the return value of FizzBuzz
        assertEquals(returnString, userService.fancyBusiness(1));
    }

This same behavior can be emulated by using Mockito using the when method. The below method specifies that when salesService.fizzBuzz is called with a value of 1, then return the value input.

   @ParameterizedTest
    @ValueSource(strings={"Fizz", "Buzz", "FizzBuzz"})
    public void fancyBusiness_getsFizzBuzzString_returnsSameString(String input) {
        Mockito.when(salesService.fizzBuzz(1)).thenReturn(input);
        Assertions.assertEquals(input, userService.fancyBusiness(1));
    }